/**
 * 
 */
package util.triemap;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Random;

import org.junit.Test;

import util.TrieMap;

/**
 * @author Joshua Lockerman
 *
 */
public class TrieMapTest {
    
    private final int MAX_STRINGS = 10000;
    private final int UNICODE_MAX = 1114111;
    
    /**
     * Test method for {@link util.TrieMap#TreeTrieMap()}.
     */
    @Test
    public void testTreeTrieMap()
    {
        TrieMap<String> map = new TrieMap<String>();
        assertNotNull(map);
    }
    
    /**
     * Test method for {@link util.TrieMap#size()}.
     */
    @Test
    public void testSize()
    {
        Random rand = new Random();
        int idealSize = rand.nextInt(MAX_STRINGS);
        TrieMap<String> map = new TrieMap<String>();
        LinkedHashSet<String> set = new LinkedHashSet<String>(idealSize);
        for(int i = 0; i < idealSize; i++) {
            boolean finished = false;
            while(!finished) {
                int length = rand.nextInt(100) + 1;
                StringBuilder builder = new StringBuilder(length);
                for(int j = 0; j < length; j++) {
                    builder.append((char) rand.nextInt(MAX_STRINGS));
                }
                String s = builder.toString();
                if(set.add(s)) {
                    finished = true;
                    map.put(s, s);
                }
            }
        }
        assertEquals(idealSize, map.size());
    }
    
    /**
     * Test method for {@link util.TrieMap#isEmpty()}.
     */
    @Test
    public void testIsEmpty()
    {
        TrieMap<String> map = new TrieMap<String>();
        assertEquals(true, map.isEmpty());
        map.put("a", "a");
        assertEquals(false, map.isEmpty());
    }
    
    /**
     * Test method for {@link util.TrieMap#containsKey(java.lang.Object)}.
     */
    @Test
    public void testContainsKey()
    {
        Random rand = new Random();
        int idealSize = rand.nextInt(MAX_STRINGS);
        TrieMap<String> map = new TrieMap<String>();
        LinkedHashSet<String> set = new LinkedHashSet<String>(idealSize);
        for(int i = 0; i < idealSize; i++) {
            boolean finished = false;
            while(!finished) {
                int length = rand.nextInt(100) + 1;
                StringBuilder builder = new StringBuilder(length);
                for(int j = 0; j < length; j++) {
                    builder.append((char) rand.nextInt(MAX_STRINGS));
                }
                String s = builder.toString();
                if(set.add(s)) {
                    finished = true;
                    assertFalse(idealSize + " " + i + " " + s, map.containsKey(s));
                    map.put(s, s);
                }
            }
        }
        for(String s : set) {
            assertEquals(true, map.containsKey(s));
        }
    }
    
    /**
     * Test method for {@link util.TrieMap#containsValue(java.lang.Object)}.
     */
    @Test
    public void testContainsValue()
    {
        Random rand = new Random();
        int idealSize = rand.nextInt(MAX_STRINGS);
        TrieMap<StringBuilder> map = new TrieMap<StringBuilder>();
        LinkedHashSet<StringBuilder> set = new LinkedHashSet<StringBuilder>(idealSize);
        for(int i = 0; i < idealSize; i++) {
            boolean finished = false;
            while(!finished) {
                int length = rand.nextInt(100) + 1;
                StringBuilder builder = new StringBuilder(length);
                for(int j = 0; j < length; j++) {
                    builder.append((char) rand.nextInt(MAX_STRINGS));
                }
                if(set.add(builder)) {
                    finished = true;
                    assertEquals(false, map.containsValue(builder));
                    map.put(builder.toString(), builder);
                }
            }
        }
        for(StringBuilder s : set) {
            assertEquals(true, map.containsKey(s.toString()));
        }
    }
    
    /**
     * Test method for {@link util.TrieMap#get(java.lang.Object)}.
     */
    @Test
    public void testGet()
    {
        Random rand = new Random();
        int idealSize = rand.nextInt(MAX_STRINGS);
        TrieMap<String> map = new TrieMap<String>();
        LinkedHashSet<String> set = new LinkedHashSet<String>(idealSize);
        for(int i = 0; i < idealSize; i++) {
            boolean finished = false;
            while(!finished) {
                int length = rand.nextInt(100) + 1;
                StringBuilder builder = new StringBuilder(length);
                for(int j = 0; j < length; j++) {
                    builder.append((char) rand.nextInt(MAX_STRINGS));
                }
                if(set.add(builder.toString())) {
                    finished = true;
                    map.put(builder.toString(), builder.toString());
                }
            }
        }
        for(String builder : set) {
            assertEquals(builder, map.get(builder.toString()));
        }
    }
    
    /**
     * Test method for {@link util.TrieMap#put(java.lang.String, java.lang.Object)}.
     */
    @Test
    public void testPut()
    {
        Random rand = new Random();
        int idealSize = rand.nextInt(MAX_STRINGS);
        TrieMap<StringBuilder> map = new TrieMap<StringBuilder>();
        LinkedHashSet<String> set = new LinkedHashSet<String>(idealSize);
        for(int i = 0; i < idealSize; i++) {
            int length = rand.nextInt(100) + 1;
            StringBuilder builder = new StringBuilder(length);
            for(int j = 0; j < length; j++) {
                builder.append((char) (rand.nextInt(95) + 32));
            }
            if(set.add(builder.toString())) {
                assertEquals(null, map.put(builder.toString(), builder));
                assertEquals(builder, map.put(builder.toString(), builder));
                assertEquals(builder, map.get(builder.toString()));
            }
            else {
                assertEquals(builder.toString(), map.put(builder.toString(), builder).toString());
            }
        }
    }
    
    /**
     * Test method for {@link util.TrieMap#remove(java.lang.Object)}.
     * 
     * @throws InterruptedException
     */
    @Test
    public void testRemove() throws InterruptedException
    {
        Random rand = new Random();
        int idealSize = rand.nextInt(MAX_STRINGS);
        TrieMap<String> map = new TrieMap<String>();
        LinkedHashSet<String> set = new LinkedHashSet<String>(idealSize);
        for(int i = 0; i < idealSize; i++) {
            boolean finished = false;
            while(!finished) {
                int length = rand.nextInt(100) + 1;
                // int length = 1;
                StringBuilder builder = new StringBuilder(length);
                for(int j = 0; j < length; j++) {
                    builder.append((char) (rand.nextInt(95) + 32));
                }
                if(set.add(builder.toString())) {
                    finished = true;
                    assertNull(map.remove(builder.toString()));
                    assertNull(map.put(builder.toString(), builder.toString()));
                    assertTrue(map.containsKey(builder.toString()));
                }
            }
        }
        int i = 0;
        for(String s : set) {
            i++;
            assertEquals(idealSize + " " + i + "", s, map.remove(s));
            assertNull(idealSize + " " + i + " " + s, map.get(s));
        }
    }
    
    /**
     * Test method for {@link util.TrieMap#putAll(java.util.Map)}.
     */
    @Test
    public void testPutAll()
    {
        // fail("Not yet implemented"); // TODO
    }
    
    /**
     * Test method for {@link util.TrieMap#clear()}.
     */
    @Test
    public void testClear()
    {
        // fail("Not yet implemented"); // TODO
    }
    
    /**
     * Test method for {@link util.TrieMap#keySet()}.
     */
    @Test
    public void testKeySet()
    {
        // fail("Not yet implemented"); // TODO
    }
    
    /**
     * Test method for {@link util.TrieMap#values()}.
     */
    @Test
    public void testValues()
    {
        Random rand = new Random();
        int idealSize = rand.nextInt(MAX_STRINGS);
        TrieMap<StringBuilder> map = new TrieMap<StringBuilder>();
        LinkedHashSet<StringBuilder> set = new LinkedHashSet<StringBuilder>(idealSize);
        for(int i = 0; i < idealSize; i++) {
            boolean finished = false;
            while(!finished) {
                int length = rand.nextInt(100) + 1;
                StringBuilder builder = new StringBuilder(length);
                for(int j = 0; j < length; j++) {
                    builder.append((char) rand.nextInt(MAX_STRINGS));
                }
                if(set.add(builder)) {
                    finished = true;
                    assertFalse(map.containsValue(builder));
                    map.put(builder.toString(), builder);
                    assertTrue(map.containsValue(builder));
                }
            }
        }
        Collection<StringBuilder> val = map.values();
        for(StringBuilder s : set) {
            assertTrue(val.contains(s));
        }
    }
    
    /**
     * Test method for {@link util.TrieMap#entrySet()}.
     */
    @Test
    public void testEntrySet()
    {
        // fail("Not yet implemented"); // TODO
    }
    
}
